home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Programming / SWI / source / src / plld.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-24  |  23.2 KB  |  1,162 lines

  1. /*  $Id: plld.c,v 1.7 1998/03/24 13:39:17 jan Exp $
  2.  
  3.     Part of SWI-Prolog
  4.     Designed and implemented by Jan Wielemaker
  5.     E-mail: jan@swi.psy.uva.nl
  6.  
  7.     Copyright (C) 1997 University of Amsterdam. All rights reserved.
  8. */
  9.  
  10. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  11. This is the source-file for  plld,   the  SWI-Prolog linker for embedded
  12. applications. See plld(1) for details.  Feel   free  to comment and send
  13. contributions.
  14.  
  15. The    file    pl-extend.c,    copied    by    the    installation    to
  16. <home>/include/stub.c  contains  a  minimal  skeleton  for  creating  an
  17. embedded application.
  18. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  19.  
  20. #ifdef WIN32
  21. #include <process.h>
  22. #include <io.h>
  23.  
  24. #define popen _popen
  25. #define pclose _pclose
  26. #define O_WRONLY _O_WRONLY
  27. #define O_RDONLY _O_RDONLY
  28. #define O_CREAT _O_CREAT
  29. #define O_TRUNC _O_TRUNC
  30. #define O_BINARY _O_BINARY
  31.  
  32. #define PROG_PL "plcon.exe"
  33. #define PROG_LD "link.exe"
  34. #define PROG_OUT "plout.exe"
  35. #define LIB_PL     "libpl.lib"
  36. #define EXT_OBJ "obj"
  37. #define OPT_DEBUG "/debug"
  38. #else /*WIN32*/
  39. #include "pl-incl.h"
  40.  
  41. #define PROG_PL "pl"
  42. #define PROG_LD cc
  43. #define PROG_OUT "a.out"
  44. #define LIB_PL    "-lpl"
  45. #define EXT_OBJ "o"
  46. #define OPT_DEBUG "-g"
  47. #ifndef O_BINARY
  48. #define O_BINARY 0
  49. #endif
  50. #endif /*WIN32*/
  51.  
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <malloc.h>
  55. #include <ctype.h>
  56. #ifdef HAVE_UNISTD_H
  57. #include <unistd.h>
  58. #endif
  59. #ifdef HAVE_SYS_TYPES_H
  60. #include <sys/types.h>
  61. #endif
  62. #ifdef HAVE_SYS_STAT_H
  63. #include <sys/stat.h>
  64. #endif
  65. #include <fcntl.h>
  66. #include <errno.h>
  67. #include <string.h>
  68. #include <signal.h>
  69.  
  70. #ifndef TRUE
  71. #define TRUE 1
  72. #define FALSE 0
  73. #endif
  74.  
  75. #ifndef MAXPATHLEN
  76. #define MAXPATHLEN 1024
  77. #endif
  78.  
  79. #define CPBUFSIZE 8192
  80.  
  81. #ifndef streq
  82. #define streq(s, q)     (strcmp((s), (q)) == 0)
  83. #endif
  84. #define strprefix(s, p) (strncmp((s), (p), strlen(p)) == 0)
  85. #ifdef WIN32
  86. #define strfeq(s, q)    (stricmp((s), (q)) == 0)
  87. #else
  88. #define strfeq(s, q)    streq(s, q)
  89. #endif
  90. #undef oserror                /* Irix name-clash */
  91. #define oserror xoserror
  92. #undef strdup
  93. #define strdup plld_strdup
  94. #define xmalloc plld_xmalloc
  95. #define xrealloc plld_xrealloc
  96. #define xfree plld_xfree
  97.  
  98. typedef struct
  99. { char **list;
  100.   int  size;
  101. } arglist;
  102.  
  103. static arglist tmpfiles;        /* list of temporary files */
  104.  
  105. static arglist ofiles;            /* object files */
  106. static arglist cfiles;            /* C input files */
  107. static arglist cppfiles;        /* C++ input files */
  108. static arglist plfiles;            /* Prolog files */
  109. static arglist qlfiles;            /* Prolog Quick Load Files */
  110.  
  111. static arglist coptions;        /* CC options */
  112. static arglist cppoptions;        /* C++ options */
  113. static arglist ldoptions;        /* LD options */
  114. static arglist ploptions;        /* PL options for saved state */
  115.  
  116. static arglist libs;            /* (C) libraries */
  117. static arglist lastlibs;        /* libs that must be at the end */
  118. static arglist libdirs;            /* -L library directories */
  119. static arglist includedirs;        /* -I include directories */
  120.  
  121. static char *pl;            /* Prolog executable */
  122. static char *cc;            /* CC executable */
  123. static char *cxx;            /* C++ executable */
  124. static char *ld;            /* The Linker */
  125. static char *plld;            /* Thats me! */
  126.  
  127. static char *plbase;            /* Prolog home */
  128. static char *plarch;            /* Prolog architecture id */
  129.  
  130. static char *plgoal;            /* -g goal */
  131. static char *pltoplevel;        /* -t goal */
  132. static char *plinitfile;        /* -f file */
  133.  
  134. static char *ctmp;            /* base executable */
  135. static char *pltmp;            /* base saved state */
  136. static char *out;            /* final output */
  137.  
  138. static int nostate = FALSE;        /* do not make a state */
  139. static int nolink = FALSE;        /* do not link */
  140.  
  141. static int verbose = TRUE;        /* verbose operation */
  142. static int fake = FALSE;        /* don't really do anything */
  143.  
  144. static void    removeTempFiles();
  145.  
  146.          /*******************************
  147.          *           ERROR        *
  148.          *******************************/
  149.  
  150. static char *
  151. oserror()
  152. {
  153. #ifdef HAVE_STRERROR
  154.   return strerror(errno);
  155. #else
  156.   extern int sys_nerr;
  157.   extern char *sys_errlist[];
  158.   extern int errno;
  159.  
  160.   if ( errno < sys_nerr )
  161.     return sys_errlist[errno];
  162.  
  163.   return "Unknown error";
  164. #endif
  165. }
  166.  
  167.  
  168. static int
  169. error(int status)
  170. { removeTempFiles();
  171.  
  172.   fprintf(stderr, "*** %s exit status %d\n", plld, status);
  173.  
  174.   exit(status);
  175.   return 1;                /* not reached */
  176. }
  177.  
  178.  
  179. static void
  180. catched_signal(int sig)
  181. { error(sig);
  182. }
  183.  
  184.  
  185.          /*******************************
  186.          *           MALLOC        *
  187.          *******************************/
  188.  
  189. static void
  190. xfree(void *mem)
  191. { if ( mem )
  192.     free(mem);
  193. }
  194.  
  195.  
  196. void *
  197. xmalloc(size_t bytes)
  198. { void *mem;
  199.  
  200.   if ( !bytes )
  201.     return NULL;
  202.   if ( (mem = malloc(bytes)))
  203.     return mem;
  204.  
  205.   fprintf(stderr, "%s: not enough memory\n", plld);
  206.   error(1);
  207.   return NULL;
  208. }
  209.  
  210.  
  211. void *
  212. xrealloc(void *old, size_t bytes)
  213. { void *mem;
  214.  
  215.   if ( !bytes )
  216.   { xfree(old);
  217.     return NULL;
  218.   }
  219.   if ( !old )
  220.   { if ( (mem = malloc(bytes)))
  221.       return mem;
  222.   } else
  223.   { if ( (mem = realloc(old, bytes)))
  224.       return mem;
  225.   }
  226.  
  227.   fprintf(stderr, "%s: not enough memory\n", plld);
  228.   error(1);
  229.   return NULL;
  230. }
  231.  
  232.  
  233.  
  234.          /*******************************
  235.          *    TEXT MANIPULATION    *
  236.          *******************************/
  237.  
  238. static char *
  239. strdup(const char *in)
  240. { return strcpy(xmalloc(strlen(in)+1), in);
  241. }
  242.  
  243.  
  244. void
  245. appendArgList(arglist *list, const char *arg)
  246. { if ( list->size == 0 )
  247.   { list->list = xmalloc(sizeof(char*) * (list->size+2));
  248.   } else
  249.   { list->list = xrealloc(list->list, sizeof(char*) * (list->size+2));
  250.   }
  251.  
  252.   list->list[list->size++] = strdup(arg);
  253.   list->list[list->size]   = NULL;
  254. }
  255.  
  256.  
  257. void
  258. prependArgList(arglist *list, const char *arg)
  259. { int n;
  260.  
  261.   if ( list->size == 0 )
  262.   { list->list = xmalloc(sizeof(char*) * (list->size+2));
  263.   } else
  264.   { list->list = xrealloc(list->list, sizeof(char*) * (list->size+2));
  265.   }
  266.   for(n=++list->size; n>0; n--)
  267.     list->list[n] = list->list[n-1];
  268.   
  269.   list->list[0] = strdup(arg);
  270. }
  271.  
  272.  
  273. void
  274. concatArgList(arglist *to, const char *prefix, arglist *from)
  275. { int n;
  276.  
  277.   for(n=0; n<from->size; n++)
  278.   { char buf[1024];
  279.  
  280.     sprintf(buf, "%s%s", prefix, from->list[n]);
  281.     appendArgList(to, buf);
  282.   }
  283. }
  284.  
  285.  
  286. void
  287. addArgs(const char *s, arglist *list)
  288. { const char *f;
  289.   char tmp[1024];
  290.  
  291.   while(*s)
  292.   { while(*s && isspace(*s))
  293.       s++;
  294.     f = s;
  295.     while(*s && !isspace(*s))
  296.       s++;
  297.     if ( s > f )
  298.     { strncpy(tmp, f, s-f);
  299.       tmp[s-f] = '\0';
  300.       appendArgList(list, tmp);
  301.     }
  302.   }
  303. }
  304.  
  305.  
  306. void
  307. addLibs(const char *s, arglist *list)
  308. { const char *f;
  309.   char tmp[1024];
  310.  
  311.   while(*s)
  312.   { while(*s && isspace(*s))
  313.       s++;
  314.     f = s;
  315.     while(*s && !isspace(*s))
  316.       s++;
  317.     if ( s > f )
  318.     { if ( s > f+2 && strprefix(f, "-l") )
  319.     f += 2;
  320.       strncpy(tmp, f, s-f);
  321.       tmp[s-f] = '\0';
  322.       appendArgList(list, tmp);
  323.     }
  324.   }
  325. }
  326.  
  327.  
  328. void
  329. appendOptions(arglist *args, const char *from)
  330. { int sep = *from++;
  331.   const char *f;
  332.   char tmp[1024];
  333.  
  334.   while(*from)
  335.   { f = from;
  336.     while(*from && *from != sep)
  337.       from++;
  338.     if ( from > f )
  339.     { strncpy(tmp, f, from-f);
  340.       tmp[from-f] = '\0';
  341.       appendArgList(args, tmp);
  342.     }
  343.     if ( *from == sep )
  344.       from++;
  345.   }
  346. }
  347.  
  348.  
  349. void
  350. ensureOption(arglist *args, const char *opt)
  351. { int n;
  352.  
  353.   for(n=0; n<args->size; n++)
  354.   { if ( streq(args->list[n], opt) )
  355.       return;
  356.   }
  357.  
  358.   appendArgList(args, opt);
  359. }
  360.  
  361.  
  362. arglist *
  363. copyArgList(arglist *in)
  364. { arglist *out = xmalloc(sizeof(arglist));
  365.   int n;
  366.  
  367.   out->size = in->size;
  368.   out->list = xmalloc(sizeof(char *) * (in->size + 1));
  369.   for(n=0; n<in->size; n++)
  370.     out->list[n] = strdup(in->list[n]);
  371.   out->list[n] = NULL;
  372.  
  373.   return out;
  374. }
  375.  
  376. void
  377. freeArgList(arglist *l)
  378. { int n;
  379.  
  380.   for(n=0; n<l->size; n++)
  381.     xfree(l->list[n]);
  382.  
  383.   xfree(l);
  384. }  
  385.  
  386.  
  387. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  388. If the filename has an extension, replace it, otherwise add the given
  389. extension.
  390. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  391.  
  392. char *
  393. replaceExtension(const char *base, const char *ext, char *buf)
  394. { char *e = NULL, *q = buf;
  395.   const char *s = base;
  396.  
  397.   for( ; *s; s++, q++ )
  398.   { *q = *s;
  399.     if ( *q == '.' )
  400.       e = q;
  401.     else if ( *q == '/' || *q == '\\' )
  402.       e = NULL;
  403.   }
  404.   *q = '\0';
  405.  
  406.   if ( e )
  407.     e++;
  408.   else
  409.   { e = q + strlen(q);
  410.     *e++ = '.';
  411.   }
  412.   
  413.   strcpy(e, ext);
  414.  
  415.   return buf;
  416. }
  417.  
  418.  
  419.  
  420.          /*******************************
  421.          *       OPTION DEFS        *
  422.          *******************************/
  423.  
  424. typedef struct
  425. { char *extension;
  426.   arglist*list;
  427. } extdef;
  428.  
  429. static extdef extdefs[] =
  430. { { EXT_OBJ,    &ofiles },
  431. #ifdef WIN32
  432.   { "lib",    &libs },
  433. #else
  434.   { "a",    &ofiles },
  435. #endif
  436.   { "c",    &cfiles },
  437.   { "cpp",    &cppfiles },
  438.   { "cxx",    &cppfiles },
  439.   { "cc",    &cppfiles },
  440. #ifndef WIN32
  441.   { "C",    &cppfiles },
  442. #endif
  443.   { "pl",    &plfiles },
  444.   { "qlf",    &qlfiles },
  445.   { NULL,    NULL }
  446. };
  447.  
  448. const char *
  449. file_name_extension(const char *in)
  450. { const char *ext = NULL;
  451.   
  452.   for( ; *in; in++)
  453.   { if ( *in == '.' )
  454.       ext = in+1;
  455.   }
  456.  
  457.   return ext;
  458. }
  459.  
  460.  
  461. int
  462. dispatchFile(const char *name)
  463. { const char *ext;
  464.  
  465.   if ( (ext = file_name_extension(name)) )
  466.   { extdef *d = extdefs;
  467.  
  468.     for( ; d->extension; d++ )
  469.     { if ( strfeq(d->extension, ext) )
  470.       { appendArgList(d->list, name);
  471.     return TRUE;
  472.       }
  473.     }
  474.   }
  475.   
  476.   return FALSE;
  477. }
  478.  
  479.  
  480.          /*******************************
  481.          *      OPTION PARSING    *
  482.          *******************************/
  483.  
  484. static void
  485. usage()
  486. { fprintf(stderr,
  487.       "usage: %s -help\n"
  488.       "       %s [options] inputfile ...\n"
  489.       "\n"
  490.       "options:\n"
  491.       "       -o out           define output file\n"
  492.       "\n"
  493.       "       -v               verbose\n"
  494.       "       -f               fake (do not run any commands)\n"
  495.       "       -g               Compile/link for debugging\n"
  496.       "       -c               Only compile C/C++ files, do not link\n"
  497.       "\n"
  498.       "       -pl prolog       Prolog to use\n"
  499.       "       -ld linker       link editor to use\n"
  500.           "       -cc compiler     compiler for C source files\n"
  501.       "       -c++ compiler    compiler for C++ source files\n"
  502.       "\n"
  503.       "       -nostate         just relink the kernel\n"
  504.       "\n"
  505.       "       -pl-options,...  Add options for Prolog\n"
  506.       "       -ld-options,...  Add options for linker\n"
  507.       "       -cc-options,...  Add options for C/C++-compiler\n"
  508.       "\n"
  509.       "       -goal goal       (Prolog) entry point\n"
  510.       "       -toplevel goal   (Prolog) abort toplevel goal\n"
  511.       "       -initfile file   (Prolog) profile file to load\n"
  512.       "\n"
  513.       "       -Dmacro          Define macro (C/C++)\n"
  514.       "       -Umacro          Undefine macro (C/C++)\n"
  515.       "       -Iincludedir     Include directory (C/C++)\n"
  516.       "       -Llibdir         Library directory (C/C++ link)\n"
  517.       "       -llib            library (C/C++)\n",
  518.     plld, plld);
  519.  
  520.   exit(1);
  521. }
  522.  
  523.  
  524. static void
  525. parseOptions(int argc, char **argv)
  526. { for( ; argc > 0; argc--, argv++ )
  527.   { char *opt = argv[0];
  528.     
  529.     if ( dispatchFile(opt) )
  530.       continue;
  531.  
  532.     if ( streq(opt, "-help") )            /* -help */
  533.     { usage();
  534.     } else if ( streq(opt, "-v") )        /* -v */
  535.     { verbose++;
  536.     } else if ( streq(opt, "-f") )        /* -f */
  537.     { fake++;
  538.     } else if ( streq(opt, "-c") )        /* -c */
  539.     { nolink++;
  540.     } else if ( streq(opt, "-g") )        /* -g */
  541.     { appendArgList(&coptions, OPT_DEBUG);
  542.       appendArgList(&cppoptions, OPT_DEBUG);
  543.       appendArgList(&ldoptions, OPT_DEBUG);
  544.     } else if ( streq(opt, "-nostate") )     /* -nostate */
  545.     { nostate = TRUE;
  546.     } else if ( streq(opt, "-o") )         /* -o out */
  547.     { if ( argc > 1 )
  548.       { out = argv[1];
  549.     argc--, argv++;
  550.       } else
  551.     usage();
  552.     } else if ( streq(opt, "-goal") )         /* -goal goal */
  553.     { if ( argc > 1 )
  554.       { plgoal = argv[1];
  555.     argc--, argv++;
  556.       } else
  557.     usage();
  558.     } else if ( streq(opt, "-toplevel") )     /* -toplevel goal */
  559.     { if ( argc > 1 )
  560.       { pltoplevel = argv[1];
  561.     argc--, argv++;
  562.       } else
  563.     usage();
  564.     } else if ( streq(opt, "-initfile") )     /* -initfile goal */
  565.     { if ( argc > 1 )
  566.       { plinitfile = argv[1];
  567.     argc--, argv++;
  568.       } else
  569.     usage();
  570.     } else if ( streq(opt, "-pl") )         /* -pl prolog */
  571.     { if ( argc > 1 )
  572.       { pl = argv[1];
  573.     argc--, argv++;
  574.       } else
  575.     usage();
  576.     } else if ( streq(opt, "-cc") )         /* -cc compiler */
  577.     { if ( argc > 1 )
  578.       { cc = argv[1];
  579.     argc--, argv++;
  580.       } else
  581.     usage();
  582.     } else if ( streq(opt, "-c++") )         /* -c++ compiler */
  583.     { if ( argc > 1 )
  584.       { cxx = argv[1];
  585.     argc--, argv++;
  586.       } else
  587.     usage();
  588.     } else if ( streq(opt, "-ld") )         /* -ld linker */
  589.     { if ( argc > 1 )
  590.       { ld = argv[1];
  591.     argc--, argv++;
  592.       } else
  593.     usage();
  594.     } else if ( strprefix(opt, "-cc-options") )
  595.     { appendOptions(&coptions, opt+strlen("-cc-options"));
  596.       appendOptions(&cppoptions, opt+strlen("-cc-options"));
  597.     } else if ( strprefix(opt, "-ld-options") )
  598.     { appendOptions(&ldoptions, opt+strlen("-ld-options"));
  599.     } else if ( strprefix(opt, "-pl-options") )
  600.     { appendOptions(&ploptions, opt+strlen("-pl-options"));
  601.     } else if ( strprefix(opt, "-I") )        /* -I<include> */
  602.     { appendArgList(&includedirs, &opt[2]);
  603.     } else if ( strprefix(opt, "-D") )        /* -D<def> */
  604.     { appendArgList(&coptions, &opt[2]);
  605.       appendArgList(&cppoptions, &opt[2]);
  606.     } else if ( strprefix(opt, "-U") )        /* -U<def> */
  607.     { appendArgList(&coptions, &opt[2]);
  608.       appendArgList(&cppoptions, &opt[2]);
  609.     } else if ( strprefix(opt, "-L") )        /* -L<libdir> */
  610.     { appendArgList(&libdirs, &opt[2]);
  611.     } else if ( streq(opt, "-lccmalloc") )    /* -lccmalloc */
  612.     { appendArgList(&lastlibs, &opt[2]);
  613.     } else if ( strprefix(opt, "-l") )        /* -l<lib> */
  614.     { appendArgList(&libs, &opt[2]);
  615.     }
  616.   }
  617. }
  618.  
  619.  
  620. static void
  621. defaultProgram(char **store, char *def)
  622. { if ( !*store )
  623.     *store = strdup(def);
  624. }
  625.  
  626.  
  627. static void
  628. defaultPath(char **store, char *def)
  629. { if ( !*store )
  630.   { char *s, *e;
  631.  
  632.     s = strdup(def);
  633.     e = s + strlen(s);
  634.     while(e>s+1 && e[-1] == '/')    /* strip terminating /'s */
  635.       e--;
  636.     *e = '\0';
  637.  
  638.     *store = s;
  639.   }
  640. }
  641.  
  642.  
  643. static void
  644. tmpPath(char **store, const char *base)
  645. { if ( !*store )
  646.   { char tmp[MAXPATHLEN];
  647.  
  648.     sprintf(tmp, "%s%d", base, (int)getpid());
  649.     *store = strdup(tmp);
  650.   }
  651. }
  652.  
  653.  
  654. static void
  655. fillDefaultOptions()
  656. { char tmp[1024];
  657.   char *defcxx = "c++";
  658.  
  659.   defaultProgram(&cc,  "cc");
  660.   if ( streq(cc, "gcc") )
  661.     defcxx = "g++";
  662.   defaultProgram(&cxx, defcxx);
  663.   defaultProgram(&ld,  PROG_LD);
  664.  
  665. #ifdef WIN32
  666.   ensureOption(&coptions, "/MD");
  667.   ensureOption(&coptions, "/DWIN32");
  668.   ensureOption(&coptions, "/nologo");
  669.   ensureOption(&ldoptions, "/nologo");
  670. #endif
  671.  
  672.   tmpPath(&ctmp,   "ctmp-");
  673.   tmpPath(&pltmp,  "pltmp-");
  674.   defaultPath(&out, PROG_OUT);
  675.  
  676.   defaultProgram(&plgoal,     "$welcome");
  677.   defaultProgram(&pltoplevel, "prolog");
  678.   defaultProgram(&plinitfile, "none");
  679.  
  680. #ifdef WIN32
  681.   sprintf(tmp, "%s/bin", plbase);
  682. #else
  683.   sprintf(tmp, "%s/runtime/%s", plbase, plarch);
  684. #endif
  685.   prependArgList(&libdirs, tmp);
  686.   sprintf(tmp, "%s/include", plbase);
  687.   prependArgList(&includedirs, tmp);
  688. }
  689.  
  690.          /*******************************
  691.          *       PROLOG OPTIONS    *
  692.          *******************************/
  693. static void
  694. getPrologOptions()
  695. { FILE *fd;
  696.   char cmd[512];
  697.  
  698.   sprintf(cmd, "%s -dump-runtime-variables", pl);
  699.   if ( verbose )
  700.     printf("\teval `%s`\n", cmd);
  701.  
  702.   if ( (fd = popen(cmd, "r")) )
  703.   { char buf[256];
  704.  
  705.     while( fgets(buf, sizeof(buf), fd) )
  706.     { char name[100];
  707.       char value[256];
  708.       char *v;
  709.  
  710.       if ( sscanf(buf, "%[^=]=%[^;\n]", name, value) == 2 )
  711.       { v = value;
  712.     if ( *v == '"' )
  713.     { char *e = ++v;
  714.  
  715.       while(*e && *e != '"')
  716.         e++;
  717.       while(e>v && isspace(e[-1]))
  718.         e--;
  719.       *e = '\0';
  720.     }
  721.     if ( streq(name, "CC") )
  722.       defaultProgram(&cc, v);
  723.     else if ( streq(name, "PLBASE") )
  724.       defaultPath(&plbase, v);
  725.     else if ( streq(name, "PLARCH") )
  726.       defaultPath(&plarch, v);
  727.     else if ( streq(name, "PLLIBS") )
  728.       addLibs(v, &libs);
  729.     else if ( streq(name, "PLLDFLAGS" ) )
  730.       appendArgList(&ldoptions, v);
  731.     else
  732.       continue;
  733.  
  734.     if ( verbose )
  735.       printf("\t\t%s=\"%s\"\n", name, v);
  736.       }    
  737.     }
  738.  
  739.     pclose(fd);
  740.   } else
  741.   { fprintf(stderr, "%s: failed to run %s: %s", plld, cmd, oserror());
  742.     error(1);
  743.   }
  744. }
  745.  
  746.          /*******************************
  747.          *         CALLING        *
  748.          *******************************/
  749.  
  750. char *
  751. shell_quote(char *to, const char *arg)
  752. { static const char needq[] = "#!|<>*?$'";
  753.   const char *s;
  754.   int needquote = FALSE;
  755.  
  756.   for(s=arg; *s; s++)
  757.   { if ( strchr(needq, *s) )
  758.     { needquote = TRUE;
  759.       break;
  760.     }
  761.   }
  762.  
  763.   if ( needquote )
  764.   { *to++ = '"';
  765.     for(s=arg; *s; s++)
  766.     { if ( *s == '"' || *s == '$' )
  767.     *to++ = '\\';
  768.       *to++ = *s;
  769.     }
  770.     *to++ = '"';
  771.     *to = '\0';
  772.     
  773.     return to;
  774.   }
  775.  
  776.   strcpy(to, arg);
  777.  
  778.   return to+strlen(to);
  779. }
  780.  
  781.  
  782.  
  783. static void
  784. callprog(const char *ld, arglist *args)
  785. { char cmd[10240];
  786.   char *e = cmd;
  787.   int n, status;
  788.  
  789.   strcpy(e, ld);
  790.   e = &e[strlen(e)];
  791.   for(n=0; n<args->size; n++)
  792.   { *e++ = ' ';
  793.     e = shell_quote(e, args->list[n]);
  794.   }
  795.  
  796.   if ( verbose )
  797.     printf("\t%s\n", cmd);
  798.  
  799.   if ( !fake )
  800.   { if ( (status=system(cmd)) != 0 )
  801.     { fprintf(stderr, "%s returned code %d\n", ld, status);
  802.       error(1);
  803.     }
  804.   }
  805. }
  806.  
  807.  
  808.          /*******************************
  809.          *        PROCESSING        *
  810.          *******************************/
  811.  
  812. static void
  813. compileFile(const char *compiler, arglist *options, const char *cfile)
  814. { char ofile[MAXPATHLEN];
  815.   char *ext;
  816.   arglist *args = copyArgList(options);
  817.  
  818.   strcpy(ofile, cfile);
  819.   if ( (ext = (char *)file_name_extension(ofile)) )
  820.     strcpy(ext, EXT_OBJ);
  821.  
  822.   prependArgList(args, "-c");
  823.   appendArgList(args, "-D__SWI_PROLOG__");
  824.   appendArgList(args, "-D__SWI_EMBEDDED__");
  825.   concatArgList(args, "-I", &includedirs);
  826.  
  827.   appendArgList(args, "-o");
  828.   appendArgList(args, ofile);
  829.   appendArgList(args, cfile);
  830.  
  831.   callprog(compiler, args);
  832.   appendArgList(&ofiles, ofile);
  833.   if ( !nolink )
  834.     appendArgList(&tmpfiles, ofile);
  835.   freeArgList(args);
  836. }
  837.  
  838.  
  839. void
  840. compileObjectFiles()
  841. { int n;
  842.  
  843.   for(n=0; n<cfiles.size; n++)
  844.     compileFile(cc, &coptions, cfiles.list[n]);
  845.   for(n=0; n<cppfiles.size; n++)
  846.     compileFile(cxx, &cppoptions, cppfiles.list[n]);
  847. }
  848.  
  849. #ifdef WIN32
  850. char *
  851. os_path(char *out, const char *in)
  852. { for(; *in; in++)
  853.   { if ( *in == '/' )
  854.       *out++ = '\\';
  855.     else
  856.       *out++ = *in;
  857.   }
  858.   *out = '\0';
  859.  
  860.   return out;
  861. }
  862.  
  863. void
  864. exportlibdirs()
  865. { char tmp[10240];
  866.   char *s, *e;
  867.   int n;
  868.  
  869.   strcpy(tmp, "LIB=");
  870.   e = tmp + strlen(tmp);
  871.  
  872.   for(n=0; n<libdirs.size; n++)
  873.   { e = os_path(e, libdirs.list[n]);
  874.     *e++ = ';';
  875.   }
  876.   if ( (s = getenv("LIB")) )
  877.     strcpy(e, s);
  878.  
  879.   if ( verbose )
  880.     printf("\t%s\n", tmp);
  881.  
  882.   putenv(strdup(tmp));
  883. }
  884. #endif
  885.  
  886. void
  887. linkBaseExecutable()
  888. { char *cout = (nostate ? out : ctmp);
  889.  
  890. #ifdef WIN32
  891. { char tmp[MAXPATHLEN];
  892.   sprintf(tmp, "/out:%s", cout);
  893.   prependArgList(&ldoptions, tmp);
  894. }
  895. #else
  896.   prependArgList(&ldoptions, cout);
  897.   prependArgList(&ldoptions, "-o");        /* -o ctmp */
  898. #endif
  899.   concatArgList(&ldoptions, "", &ofiles);    /* object files */
  900. #ifdef WIN32
  901.   exportlibdirs();
  902. #else
  903.   concatArgList(&ldoptions, "-L", &libdirs);    /* library directories */
  904. #endif
  905.   appendArgList(&ldoptions, LIB_PL);        /* -lpl */
  906. #ifdef WIN32
  907.   concatArgList(&ldoptions, "", &libs);        /* libraries */
  908. #else
  909.   concatArgList(&ldoptions, "-l", &libs);    /* libraries */
  910. #endif
  911. #ifdef WIN32
  912.   concatArgList(&ldoptions, "", &lastlibs);    /* libraries */
  913. #else
  914.   concatArgList(&ldoptions, "-l", &lastlibs);    /* libraries */
  915. #endif
  916.  
  917.   if ( !nostate )
  918.   { appendArgList(&tmpfiles, ctmp);    /* register for deletion */
  919. #ifdef WIN32
  920.     {                    /* schedule .exp file for deletion */
  921.       char buf[MAXPATHLEN];
  922.       appendArgList(&tmpfiles, replaceExtension(ctmp, "exp", buf));
  923.       appendArgList(&tmpfiles, replaceExtension(ctmp, "lib", buf));
  924.     }
  925. #endif
  926.   }
  927.  
  928.   callprog(ld, &ldoptions);
  929. }
  930.  
  931.  
  932. static void
  933. quoted_name(const char *name, char *plname)
  934. { int needquote = TRUE;
  935.  
  936.   if ( islower(name[0]) )
  937.   { const char *s = name+1;
  938.  
  939.     for( ; *s && (isalnum(*s) || *s == '_'); s++)
  940.       ;
  941.     if ( *s == '\0' )
  942.       needquote = FALSE;
  943.   }
  944.  
  945.   if ( !needquote )
  946.     strcpy(plname, name);
  947.   else
  948.   { char *o = plname;
  949.  
  950.     *o++ = '\'';
  951.     for( ; *name; name++)
  952.     { if ( *name == '\'' )
  953.     *o++ = *name;
  954.       *o++ = *name;
  955.     }
  956.     *o++ = '\'';
  957.     *o = '\0';
  958.   }
  959. }
  960.  
  961.  
  962. char *
  963. put_pl_option(char *to, const char* name, const char *value)
  964. { strcpy(to, name);
  965.   to += strlen(to);
  966.   *to++ = '=';
  967.   quoted_name(value, to);
  968.   to += strlen(to);
  969.  
  970.   return to;
  971. }
  972.  
  973.  
  974. void
  975. createSavedState()
  976. { char buf[1024];
  977.   char *e;
  978.   int n;
  979.  
  980.   strcpy(buf, "consult([");
  981.   e = buf + strlen(buf);
  982.   for(n=0; n<plfiles.size; n++)
  983.   { if ( n > 0 )
  984.       *e++ = ',';
  985.     quoted_name(plfiles.list[n], e);
  986.     e += strlen(e);
  987.   }
  988.   strcpy(e, "]),qsave_program(");
  989.   e += strlen(e);
  990.   quoted_name(pltmp, e);
  991.   e += strlen(e);
  992.   strcpy(e, ",[");
  993.   e += strlen(e);
  994.   e = put_pl_option(e, "goal",     plgoal);
  995.   *e++ = ',';
  996.   e = put_pl_option(e, "toplevel", pltoplevel);
  997.   *e++ = ',';
  998.   e = put_pl_option(e, "initfile", plinitfile);
  999.   strcpy(e, "])");
  1000.   e += strlen(e);
  1001.  
  1002.   appendArgList(&ploptions, "-f");
  1003.   appendArgList(&ploptions, "none");
  1004.   appendArgList(&ploptions, "-F");
  1005.   appendArgList(&ploptions, "none");
  1006.   appendArgList(&ploptions, "-g");
  1007.   appendArgList(&ploptions, "true");
  1008.   appendArgList(&ploptions, "-t");
  1009.   appendArgList(&ploptions, buf);
  1010.  
  1011.   appendArgList(&tmpfiles, pltmp);        /* register for deletion */
  1012.  
  1013.   callprog(pl, &ploptions);
  1014. }
  1015.  
  1016.  
  1017. static void
  1018. copy_fd(int i, int o)
  1019. { char buf[CPBUFSIZE];
  1020.   int n;
  1021.  
  1022.   while( (n=read(i, buf, sizeof(buf))) > 0 )
  1023.   { while( n > 0 )
  1024.     { int n2;
  1025.  
  1026.       if ( (n2 = write(o, buf, n)) > 0 )
  1027.       { n -= n2;
  1028.       } else
  1029.       { fprintf(stderr, "%s: write failed: %s\n", plld, oserror());
  1030.     error(1);
  1031.       }
  1032.     }
  1033.   }
  1034.  
  1035.   if ( n < 0 )
  1036.   { fprintf(stderr, "%s: read failed: %s\n", plld, oserror());
  1037.     error(1);
  1038.   }
  1039. }
  1040.  
  1041.  
  1042. void
  1043. createOutput()
  1044. { int ifd, ofd = -1;
  1045.  
  1046.   if ( verbose )
  1047.   {
  1048. #ifdef WIN32
  1049.     printf("\tcopy /b %s+%s %s\n", ctmp, pltmp, out);
  1050. #else
  1051.     printf("\tcat %s %s > %s\n", ctmp, pltmp, out);
  1052. #endif
  1053.   }
  1054.  
  1055.   if ( !fake )
  1056.   { if ( (ofd = open(out, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666)) < 0 )
  1057.     { fprintf(stderr, "Could not open %s: %s\n", out, oserror());
  1058.       error(1);
  1059.     }
  1060.     if ( (ifd = open(ctmp, O_RDONLY|O_BINARY)) < 0 )
  1061.     { close(ofd);
  1062.       remove(out);
  1063.       fprintf(stderr, "Could not open %s: %s\n", ctmp, oserror());
  1064.       error(1);
  1065.     }
  1066.     copy_fd(ifd, ofd);
  1067.     close(ifd);
  1068.     if ( (ifd = open(pltmp, O_RDONLY|O_BINARY)) < 0 )
  1069.     { close(ofd);
  1070.       remove(out);
  1071.       fprintf(stderr, "Could not open %s: %s\n", pltmp, oserror());
  1072.       error(1);
  1073.     }
  1074.     copy_fd(ifd, ofd);
  1075.     close(ifd);
  1076.   }
  1077.  
  1078. #ifdef HAVE_CHMOD
  1079.   { int mask = umask(0777);
  1080.     
  1081.     umask(mask);
  1082.  
  1083.     if ( verbose )
  1084.       printf("\tchmod %03o %s\n", 0777 & ~mask, out);
  1085.  
  1086.     if ( !fake )
  1087.     { if ( fchmod(ofd, 0777 & ~mask) != 0 )
  1088.       { fprintf(stderr, "Could make %s executable: %s\n", out, oserror());
  1089.     error(1);
  1090.       }
  1091.     }
  1092.   }
  1093. #endif
  1094.  
  1095.   if ( !fake )
  1096.     close(ofd);
  1097. }
  1098.  
  1099.  
  1100. static void
  1101. removeTempFiles()
  1102. { int n;
  1103.  
  1104.   for(n = 0; n < tmpfiles.size; n++)
  1105.   { if ( verbose )
  1106.       printf("\trm -f %s\n", tmpfiles.list[n]);
  1107.     remove(tmpfiles.list[n]);
  1108.   }
  1109. }
  1110.  
  1111.          /*******************************
  1112.          *           SIGNALS        *
  1113.          *******************************/
  1114.  
  1115. static void
  1116. catchSignals()
  1117. { signal(SIGINT,    catched_signal);
  1118.   signal(SIGSEGV,    catched_signal);
  1119. }
  1120.  
  1121.  
  1122.          /*******************************
  1123.          *           MAIN        *
  1124.          *******************************/
  1125.  
  1126. int
  1127. main(int argc, char **argv)
  1128. { plld = argv[0];
  1129.   
  1130.   argc--;
  1131.   argv++;
  1132.  
  1133.   catchSignals();
  1134.  
  1135.   if ( argc == 0 )
  1136.   { fprintf(stderr, "No input files.  Use %s -help.\n", plld);
  1137.     exit(0);
  1138.   }
  1139.  
  1140.   putenv("PLLD=true");            /* for subprograms */
  1141.  
  1142.   verbose = FALSE;
  1143.   parseOptions(argc, argv);
  1144.   defaultProgram(&pl, PROG_PL);
  1145.   getPrologOptions();
  1146.   fillDefaultOptions();
  1147.  
  1148.   compileObjectFiles();
  1149.   if ( !nolink )
  1150.   { linkBaseExecutable();
  1151.  
  1152.     if ( !nostate )
  1153.     { createSavedState();
  1154.       createOutput();
  1155.     }
  1156.   }
  1157.  
  1158.   removeTempFiles();
  1159.  
  1160.   return 0;
  1161. }
  1162.